Introduction

Background

This project was done as a part of “Data Analysis” course as part of our teams studies in Digital Sciences for High-Tech in the University of Tel-Aviv. Our team has great interest in using our studies for exploring and in the future maybe even developing tools for improving the way we treat our planet. Therefore our subject is CO2 emissions in congestion with the world happiness index.

Goals

  1. Find the trends of CO2 emissions in different countries along the years 1700-2017.
  2. Find what countries had greater growth in emissions and in which years.
  3. Compare the leading countries with the highest recent trends of growth or decreased emission in correlation with the current and previous UN happiness Index.

Part 1: Importing Data and Packages

Data import

happy_index_2005 <- "Data/world-happiness-report-2005-2020.csv" 
happy_index_2021 <- "Data/world-happiness-report-2021.csv"
emission <- "Data/co2_emission.csv"
population <-"Data/population.csv"

df_2005 <- read.csv(happy_index_2005)
df_2021 <- read.csv(happy_index_2021)
df_emiss <- read.csv(emission, col.names = c("Entity", "Code" , "Year", "co2"))
df_pop <- read.csv(population, col.names = c("Entity", "Code" , "Year", "Population"))

The first Data consists of the UN happiness index for the years 2005-2017.

as_tibble(df_2005)

The second data is the happiness index report for 2021.

as_tibble(df_2021)

The third data contains CO2 emissions from around 1700 up until 2017, by countries and continents.

as_tibble(df_emiss)

The final data is a list of population sizes by countries for about the same years as the CO2 data.

as_tibble(df_pop)

As seen in the table above, the main dataset regarding emissions has only 4 features, of which 2 are identical (countries and country code). We will now examine the summary of it’s characteristics:

summary(df_emiss)
    Entity              Code                Year           co2            
 Length:20853       Length:20853       Min.   :1751   Min.   :-6.255e+08  
 Class :character   Class :character   1st Qu.:1932   1st Qu.: 3.188e+05  
 Mode  :character   Mode  :character   Median :1971   Median : 3.829e+06  
                                       Mean   :1953   Mean   : 1.931e+08  
                                       3rd Qu.:1995   3rd Qu.: 3.707e+07  
                                       Max.   :2017   Max.   : 3.615e+10  

As seen above, we can see the minimal year, minimal amount of CO2 emissions. Also shown are mean and max values. We also learn about the size of the data, around ~21k rows.

Part 2: Tidying the Data

Tidying Functions

 [1] "ï..Country.name"                  "year"                             "Life.Ladder"                      "Log.GDP.per.capita"              
 [5] "Social.support"                   "Healthy.life.expectancy.at.birth" "Freedom.to.make.life.choices"     "Generosity"                      
 [9] "Perceptions.of.corruption"        "Positive.affect"                  "Negative.affect"                 
Joining, by = "Entity"

We have just created the two main datasets to work with, which includes important features from all of the previous datasets and some features that we have created above:

  1. “df_all” which include all data per country per year from 1950 until 2017, introducing some new features:
  • Population, taken from the population’s DF
  • CO2/Population ratio, calculated.
  • “Diff” column, which shows the difference between the previous and the current year emissions for each consecutive year.
  1. “df_merge”, which includes data for each country regarding:
  • The average ratio feature, which is calculated from 1950 to 2017 using the previously explained “ratio” feature.
  • The difference in co2 emission this period and the life-ladder in 2017.
  • The average population in those years.
  • The average CO2 emissions.
  • The 2017’s “Life.Ladder” - happiness index score.
  • “Sum.Dif” - summing over the diff feature.

We also made a choice to limit our data regarding emissions to after 1950. The reason is that the rise in values is almost exponential after the years of WW2. When plotted on a graph, placing values from before and after 1950 they become incomparable.

The summary for df_merge:

summary(df_merge)
    Entity            avg.ratio        avg.Population         avg.co2           Life.Ladder       sum.dif          
 Length:138         Min.   : 0.03123   Min.   :2.900e+05   Min.   :2.539e+05   Min.   :2.662   Min.   :-675355128  
 Class :character   1st Qu.: 0.67361   1st Qu.:4.486e+06   1st Qu.:4.375e+06   1st Qu.:4.593   1st Qu.:    142380  
 Mode  :character   Median : 3.04396   Median :9.762e+06   Median :2.017e+07   Median :5.587   Median :   6399728  
                    Mean   : 4.87430   Mean   :4.360e+07   Mean   :1.902e+08   Mean   :5.463   Mean   : 102976353  
                    3rd Qu.: 7.70521   3rd Qu.:2.873e+07   3rd Qu.:9.600e+07   3rd Qu.:6.262   3rd Qu.:  28576960  
                    Max.   :25.67181   Max.   :1.296e+09   Max.   :5.558e+09   Max.   :7.788   Max.   :7786512016  

And for df_all:

summary(df_all)
    Entity              Code                Year           co2                  Diff              Population            ratio        
 Length:17854       Length:17854       Min.   :1950   Min.   :-6.255e+08   Min.   :-600971748   Min.   :1.000e+03   Min.   :  0.000  
 Class :character   Class :character   1st Qu.:1967   1st Qu.: 4.746e+05   1st Qu.:     -9810   1st Qu.:2.400e+05   1st Qu.:  0.408  
 Mode  :character   Mode  :character   Median :1984   Median : 4.430e+06   Median :     43968   Median :3.386e+06   Median :  1.841  
                                       Mean   :1984   Mean   : 2.423e+08   Mean   :   5310082   Mean   :6.108e+07   Mean   :  5.211  
                                       3rd Qu.:2002   3rd Qu.: 4.593e+07   3rd Qu.:   1018269   3rd Qu.:1.230e+07   3rd Qu.:  6.384  
                                       Max.   :2019   Max.   : 3.615e+10   Max.   :1543508239   Max.   :7.713e+09   Max.   :403.351  
                                                      NA's   :3595         NA's   :3595         NA's   :914         NA's   :4509     

Part 3: Proccesing of the Data

Visualisation

Countries of the World

In this plot the different countries in the data are shown in deeper colors for higher values of emission to population ratio in the year of 2017:

d = df_all %>%
  filter(Year==2017)

l <- list(color = toRGB("grey"), width = 0.2)

# specify map projection/options

g <- list(
  showframe = FALSE,
  showcoastlines = FALSE,
  projection = list(type = 'Mercator')
)

p <- plot_geo(d) %>%
  add_trace(
    z = ~ratio, color = ~ratio, colors = 'Reds',
    text = ~Entity, locations = ~Code, marker = list(line = l)
  ) %>%
  colorbar(title = 'CO2/Population', thickness=15) %>%
  layout(
    title = 'World Ratio of CO2/Population',
    geo = g,
    autosize = F
  )
p <- ggplotly(p, width = 3000, height = 1500, automargin = TRUE)
p

As we can see, some of the leading countries in CO2/Population ratio are Qatar, United Arab Emirates, Kuwait, USA, Saudi Arabia, Canada, Kazakhstan and Australia with above 15 units of CO2/population. That means countries like China and India - whose CO2 emission rate is very high compared to other countries - are ranked lower, even though they are more polluting in net amount.

Countries Emission vs Population by Years and Continents

For comfortably displaying the data, each country is allocated to it’s fitting continent and a color.

fig <- d %>%
  plot_ly(
    x = ~co2, 
    y = ~Population, 
    size = ~ratio,
    frame = ~Year, 
    text = ~Entity, 
    color = ~continent,
    type = 'scatter',
    mode = 'markers',
    height = 500,
    width = 900,
    automargin = TRUE 
  )

fig <- fig %>% layout(
      title = "Yearly CO2 Emissions by Countries vs Population",
      xaxis = list(
      type = "log"
      # autosize = F
    )
  )

fig

We would like to develop this graph forward and see it with correlation to the life ladder index from 2005-2017. For this purpose we would like to create another df, containing both happiness index scores and data from “df_all”, which contains continents data as well now:

We get the following plot:

fig <- plot_ly(
    data = df_2005_2017,
    x = ~co2, 
    y = ~Life.Ladder, 
    size = ~ratio,
    frame = ~Year, 
    text = ~Entity, 
    color = ~continent,
    type = 'scatter',
    mode = 'markers',
    height = 500,
    width = 900,
    automargin = TRUE 
  )

fig <- fig %>% layout(
      title = "Yearly CO2 Emissions by Countries vs Life Ladder",
      xaxis = list(
      type = "log"
    )
  )

fig

This graph shows the CO2 emissions of each country compared to it’s population and Life Ladder score. If we look at the United States for example, it seems that while the population has increased, the level of pollution has decreased.

And yet another scatter plot for different countries:

df_3d <- df_2005_2017 %>%
  filter(Year == 2017)

fig <- df_3d %>%
  plot_ly(
    x = ~Population, 
    y = ~ratio, 
    z = ~Life.Ladder,
    # size = ~Life.Ladder,
    # frame = ~Entity, 
    text = ~Entity, 
    color = ~continent,
    height = 500,
    width = 900,
    automargin = TRUE 
  )

fig <- fig %>% layout(
      title = "CO2 Emissions vs Life Ladder, Filtered by Countries, 2017"
    )

fig <- fig %>% add_markers()
fig

Commulative Emissions by Countries Over the Years 1950-2017


d <- df_all %>%
  filter(Entity != "World") %>%
  filter(co2 != 0)
d
pp <- streamgraph(d, key="Entity",
                  order = "asis",
                  value="co2", 
                  date="Year",
                  offset="zero",
                  sort="co2"
                  ) %>%
  sg_axis_y(tick_format = "e")  %>%
  sg_legend(show=TRUE, label="Country: ") %>%
  sg_title("CO2 Emissions by Years and Countries, 1950-2017")

pp
streamgraph_html returned an object of class `list` instead of a `shiny.tag`.streamgraph_html returned an object of class `list` instead of a `shiny.tag`.
CO2 Emissions by Years and Countries, 1950-2017

This plot shows the accumulation of emissions year after year, from 1950 to 2017 for different countries.

Yearly in CO2 Emissions for Top 10 Polluting Countries

top_emiss_2017 <- df_emiss %>%
  filter(Year == 2017) %>%
  filter(Code != '') %>%
  filter(Entity != "World") %>%
  top_n( 10, co2) %>%
  arrange(desc(co2)) %>%
  head(10)
  
top_countries = top_emiss_2017$Entity
g <- ggplot(data = df_emiss[df_emiss$Entity %in% top_countries, ] 
                          , aes(x = Year, y = co2, group = Entity)) + 
    geom_line() +
    labs(title = "Top 10 Countries by CO2 Emissions") + 
    geom_line(aes(col = Entity)) +
    theme_ipsum()
g <- ggplotly(g, height = 500,
    width = 900,
    automargin = TRUE)
g
g <- ggplot(data = df_all[df_all$Entity %in% top_countries, ] 
                          , aes(x = Year, y = ratio, group = Entity)) + 
    geom_line(aes(col = Entity)) + 
    labs(title = "Top 10 Countries by CO2 Emissions to Population ratio") +
    theme_ipsum()

g <- ggplotly(g, height = 500,
    width = 900,
    automargin = TRUE)
g
NA

According to these two graphs, using the CO2/Population ratio we can see that Saudi Arabia for example has a lower population than china, but in terms of pollution per person in 2017 Saudi Arabia had the highest emission per person ratio in the world.

Boxplot for top 10 Countries


d <- df_all[df_all$Entity %in% top_countries, ] 
fig <- plot_ly(d,
               x = ~Entity,
               y = ~Diff,
               type = "box",
               color = ~Year,
               height = 500,
                width = 900,
                automargin = TRUE)

fig <- fig %>%  layout(
  title = "Difference in Emission for Top 10 Polluting Countries",
  boxmode = "group")
fig
NA

Top 10 Happiest countries Emmissions by Years

This graph takes the 10 happiest countries and shows the distribution of CO2 emissions difference level of emission between 1950 and 2017.


top_10_happiness <- df_merge %>%
  filter(rank(desc(Life.Ladder))<=10)

g <- ggplot(data = df_emiss[df_emiss$Entity %in% top_10_happiness$Entity, ] 
                          , aes(x = Year, y = co2, group = Entity)) + 
    geom_line() +
    labs(title = "Top 10 happiness Countries by CO2 Emissions") + 
    theme_ipsum() +
    geom_line(aes(col = Entity))
g <- ggplotly(g, height = 500,
    width = 900,
    automargin = TRUE)
g

In this section we are going to suggest two types of correlation based on our exploration of the data:

  1. There is correlation between the total trend of emissions and the current happiness index.
  2. There is correlation between current emission normalized by the population to the current happiness index.
g <- ggplot(data = df_merge, aes(x = avg.ratio, y = Life.Ladder)) + 
    geom_point(aes(colour = Entity)) + 
    labs(title = "Average Ratio vs Happiness Index") +
    theme_ipsum() 
g <- ggplotly(g, height = 500,
    width = 900,
    automargin = TRUE)
g

In the following plot we have removed china and India because they are sort of “outliers” in a sense that they have displayed much larger grow in emissions compared to other countries, therefore making it very hard to display on the same plot.

df <- subset(df_merge, Entity != "China" & Entity != "India" )

g <- ggplot(data = df, aes(x = Life.Ladder , y = sum.dif)) + 
    geom_point(aes(colour = Entity)) + 
    labs(title = "Sum of Emissions Difference vs 2017 Happiness Index (China, India ex.)") +
    theme_ipsum()
g <- ggplotly(g, height = 500,
    width = 900,
    automargin = TRUE)
g

# Part 4: Modeling

We are now going to introduce the linear model:

linearmod  <- lm(Life.Ladder ~ avg.ratio, data=df_merge)

summary(linearmod)

Call:
lm(formula = Life.Ladder ~ avg.ratio, data = df_merge)

Residuals:
    Min      1Q  Median      3Q     Max 
-2.2447 -0.6262 -0.0959  0.6765  2.1682 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  4.88716    0.10612  46.055  < 2e-16 ***
avg.ratio    0.11818    0.01416   8.346 7.09e-14 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.9468 on 136 degrees of freedom
Multiple R-squared:  0.3387,    Adjusted R-squared:  0.3338 
F-statistic: 69.65 on 1 and 136 DF,  p-value: 7.093e-14
confint(linearmod, level=0.95)
                 2.5 %    97.5 %
(Intercept) 4.67731147 5.0970157
avg.ratio   0.09017982 0.1461869
p <- plot_ly(
  x = fitted(linearmod),
  y = residuals(linearmod),
  height = 500,
    width = 900,
    automargin = TRUE)

p<- p %>% layout(
  title = "Residual plot for the Linear Model",
  autosize = T,
  yaxis = list(title = 'Residuals'),
  xaxis = list(title = 'Fitted Linear Model')
  
)

p

According to the graph shown above, the point distances from the X-axis are relatively equal. It’s not unequivocally, however, we state that this graph is homoscedastic.

TODO add here EXPLANATION

The residual plot shows no signs of

g <- ggplot(df_merge, aes(x = avg.ratio, y = Life.Ladder)) +
  geom_point(aes(colour = Entity)) + 
  theme_bw() +
  stat_smooth(method = "lm") + 
  labs(title = "Linear Modelling Happiness Index and Average Ratio")
g <- ggplotly(g, height = 500,
    width = 900,
    automargin = TRUE)
`geom_smooth()` using formula 'y ~ x'
g
NA
NA

According to the model, it can be seen that the correlation between the happiness index and the CO2 emission is not high, but it does exist. We will discuss it in the conclusions section.


numeric_tidy <- df_merge[-1]

corr_data <- cor(numeric_tidy)

g <- ggcorrplot(corr_data, hc.order = TRUE, type = "lower",
   outline.col = "white") +
  labs(title = "Correlation Matrix") +
  theme_ipsum()

ax <- list(
  title = "",
  showgrid = FALSE)
  
g <- ggplotly(g, height = 500,
    width = 900,
    automargin = TRUE) %>%
  layout(xaxis=ax, yaxis=ax)
g
NA
NA

We can see in the matrix above that there are some correlation that are easy to explain, such as a pretty strong one between the sum of differences regarding emissions over the test period, to the average size of population. There is also a weaker but existing correlation between the life ladder scale and the average ratio of CO2/Population size. The following section presents another model and its summary:

gmod  <- lm(Life.Ladder ~ log(avg.ratio), data=df_merge)

summary(gmod)

Call:
lm(formula = Life.Ladder ~ log(avg.ratio), data = df_merge)

Residuals:
     Min       1Q   Median       3Q      Max 
-2.03388 -0.55089  0.04812  0.59537  1.89653 

Coefficients:
               Estimate Std. Error t value Pr(>|t|)    
(Intercept)     5.15234    0.07550   68.25   <2e-16 ***
log(avg.ratio)  0.48724    0.04229   11.52   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.8283 on 136 degrees of freedom
Multiple R-squared:  0.4939,    Adjusted R-squared:  0.4902 
F-statistic: 132.7 on 1 and 136 DF,  p-value: < 2.2e-16
#plot x

p <- qplot(x = avg.ratio, Life.Ladder, data=df_merge)
p <- p + geom_smooth(method = "glm", formula = y~log(x), family = binomial(link = 'log')) +
  geom_point(aes(colour=Entity)) +
  theme_ipsum() +
  labs(title = "Linear Regression Model - Average Ratio to Life Ladder Score")
p <- ggplotly(p, height = 500,
    width = 900,
    automargin = TRUE)
p

On this model, We can see a weak correlation, but an existing one to the logistic regression. Interestingly enough, The “happiest” countries seem to have a higher ratio of CO2 emissions as well. Also worth mentioning from this plot: * The US is located far right on this map, meaning it’s emitting a lot of CO2 in proportion to its population, but it is pretty high on the happiness index as well. * Kuwait, being the leader of this unfortunate characteristic, also has a pretty decent Life Ladder score.

Testing the Top 30 Happiest Countries

To further check existing correlation, we would compare the differences between the 30 top rated countries in the happiness index and their avg.ratio of CO2/Population. In this case, we have two unrelated (i.e., independent or unpaired) groups of samples. Therefore, it is possible to use an independent t-test to evaluate how their means differ.

  • \(mA\) - Weighted average of the 30 most happiest countries.
  • \(mB\) - Weighted average of the rest of the countries.

Our research questions:

  • Is the mean avg.ratio of top 30 happiest countries (\(mA\)) is greater than the mean of other countries (\(mB\))?

  • Is the weighted average of the 30 happiest countries (\(mA\)) greater than the weighted average of the other countries (\(mB\))?

H0: \(mA\)\(mB\) - The null hypothesis

Ha: \(mA\) < \(mB\) (less) - The alternative hypothesis

top_30_happiness <- df_merge %>%
  filter(rank(desc(Life.Ladder))<=30)

# Create a data frame
T_data <- df_merge %>%
  select(Entity, avg.ratio,) %>%
  mutate(group = ifelse(Entity %in% top_30_happiness$Entity, "Top 30 Contries", "Other Countries")) 

g <- ggboxplot(T_data, x = "group", y = "avg.ratio", 
          color = "group", palette = c("#00AFBB", "#E7B800"),
        ylab = "avg. ratio", xlab = "Group") +
  theme_ipsum() +
  labs(title = "Average Ratio Compared - Top 30 Countries vs Other Countries")

g <- ggplotly(g, height = 500,
    width = 900,
    automargin = TRUE)
g
NA
NA

Although not dramatic, it is obvious that some correlation does exist. We would like to further check:

  • Do the two group have the same variances?
  • We will use F-test to test for homogeneity in variances.
res.ftest <- var.test(avg.ratio ~ group, data = T_data)
res.ftest

    F test to compare two variances

data:  avg.ratio by group
F = 0.64534, num df = 107, denom df = 29, p-value = 0.112
alternative hypothesis: true ratio of variances is not equal to 1
95 percent confidence interval:
 0.3405023 1.1067142
sample estimates:
ratio of variances 
         0.6453379 

The p-value of F-test is p = 0.112 which is greater than the significance level 0.05. In conclusion, there is no significant difference between the variances of the two data sets. Therefore, we used the T-test and assumed that the variances are equal - according to case 2 of hypothesis testing.


# Compute t-test
res <- t.test(avg.ratio ~ group, data = T_data, var.equal = TRUE, alternative = "less")
res

    Two Sample t-test

data:  avg.ratio by group
t = -5.2316, df = 136, p-value = 3.103e-07
alternative hypothesis: true difference in means is less than 0
95 percent confidence interval:
      -Inf -3.860236
sample estimates:
mean in group Other Countries mean in group Top 30 Contries 
                     3.646415                      9.294677 

The p-value of the test is \(3.103e-07\), which is less than the significance level \(\alpha = 0.05\). We can conclude that top 30 average avg.ratio is significantly different from the other countries average avg.ratio with a \(pvalue = 3.103e-07\).

Conclussion

Generally, regarding our base assumptions, we were surprised to see that they were actually not only wrong, but almost opposite. while very undeveloped countries, like countries in Africa mostly, have a very low pollution index and life ladder index. On the other hand, some very developed countries have higher values on both indexes. There are also a lot of countries who don’t fit those assumptions at all.

Despite this, our final tests did show some weak correlation within the top 30 countries as shown.

we stipulate that these weak correlations are caused partially because of the fact that the happiness index is a survey based data. it means that it is possible that the citizens of a country are not necessarily aware of the CO2 pollution and it’s consequences. There are also other factors that affect the happiness index like welfare , corruption, health services, wealth etc.

On the other hand: 1. It can be assumed that a country that emits more CO2 is a more modern and technologically advanced country, therefore it is more established, its citizens feel a sense of progress, and that causes the happiness index to rise. 2. In more polluting countries - it is a possible that there are more workplaces, therefore these countries will have a lower unemployment rate - which can in turn increase the level of happiness index within the country.

In conclusion, in our opinion, the people may be aware of their country CO2 emissions, yet it doesn’t necessarily show in the happiness index survey.

Another thing to consider is that environmental preservation, pollution reduction and global warming are quite trending in the last few years, but this is a very complex system of dependencies, and the rate of which changes are noticeable is rapidly changing. It is unknown whether we have crossed the non-return point for making the planet too hot to live at due to those emissions, but time will tell.

LS0tDQp0aXRsZTogIkdsb2JhbCBUcmVuZHMgb2YgQ08yIEVtaXNzaW9uIGFuZCBFZmZlY3RzIG9uIHRoZSBHbG9iYWwgSGFwaW5uZXMgSW5kZXgiDQphdXRob3I6ICJHdXkgS3JvdGhhbW1lciwgWWFyZGVuIEthdGFzaCwgR3V5IERhaGFuIg0Kc3VidGl0bGU6IERhdGEgQW5hbHlzaXMgUHJvamVjdCAtIERpZ2l0YWwgU2NpZW5jZXMgZm9yIEhpZ2h0ZWNoDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCiAgICBkZl9wcmludDogcGFnZWQNCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHllcw0KICAgIG51bWJlcl9zZWN0aW9uOiBubw0KICAgIGRmX3ByaW50OiBrYWJsZQ0KICAgIGZvbnRzaXplOiAxMXB0DQogICAgdGhlbWU6IHVuaXRlZA0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KZWRpdG9yX29wdGlvbnM6DQogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUNCi0tLQ0KDQojIEludHJvZHVjdGlvbg0KDQojIyBCYWNrZ3JvdW5kDQoNClRoaXMgcHJvamVjdCB3YXMgZG9uZSBhcyBhIHBhcnQgb2YgIkRhdGEgQW5hbHlzaXMiIGNvdXJzZSBhcyBwYXJ0IG9mIG91ciB0ZWFtcyANCnN0dWRpZXMgaW4gRGlnaXRhbCBTY2llbmNlcyBmb3IgSGlnaC1UZWNoIGluIHRoZSBVbml2ZXJzaXR5IG9mIFRlbC1Bdml2LiANCk91ciB0ZWFtIGhhcyBncmVhdCBpbnRlcmVzdCBpbiB1c2luZyBvdXIgc3R1ZGllcyBmb3IgZXhwbG9yaW5nIGFuZCBpbiB0aGUgZnV0dXJlIG1heWJlIGV2ZW4NCmRldmVsb3BpbmcgdG9vbHMgZm9yIGltcHJvdmluZyB0aGUgd2F5IHdlIHRyZWF0IG91ciBwbGFuZXQuIFRoZXJlZm9yZSBvdXIgc3ViamVjdCBpcw0KQ08yIGVtaXNzaW9ucyBpbiBjb25nZXN0aW9uIHdpdGggdGhlIHdvcmxkIGhhcHBpbmVzcyBpbmRleC4gDQoNCiMjIEdvYWxzDQoNCjEuIEZpbmQgdGhlIHRyZW5kcyBvZiBDTzIgZW1pc3Npb25zIGluIGRpZmZlcmVudCBjb3VudHJpZXMgYWxvbmcgdGhlIHllYXJzIDE3MDAtMjAxNy4NCjIuIEZpbmQgd2hhdCBjb3VudHJpZXMgaGFkIGdyZWF0ZXIgZ3Jvd3RoIGluIGVtaXNzaW9ucyBhbmQgaW4gd2hpY2ggeWVhcnMuDQozLiBDb21wYXJlIHRoZSBsZWFkaW5nIGNvdW50cmllcyB3aXRoIHRoZSBoaWdoZXN0IHJlY2VudCB0cmVuZHMgb2YgZ3Jvd3RoIG9yIGRlY3JlYXNlZCBlbWlzc2lvbg0KaW4gY29ycmVsYXRpb24gd2l0aCB0aGUgY3VycmVudCBhbmQgcHJldmlvdXMgVU4gaGFwcGluZXNzIEluZGV4LiANCg0KIyBQYXJ0IDE6IEltcG9ydGluZyBEYXRhIGFuZCBQYWNrYWdlcw0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcud2lkdGg9NjAwLCBmaWcuaGVpZ2h0PTQwMCwgZmlnLmFsaWduID0gImNlbnRlciIsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFKSANCmBgYA0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCiMgaW5zdGFsbCBhbmQgaW1wb3J0IHBhY2thZ2VzDQoNCmluc3RhbGwucGFja2FnZXMoYygiY293cGxvdCIsICJnZ2FsdCIsICJnZ2FsdCIsICJHR2FsbHkiLCAiSG1pc2MiLCAiSVNMUiIsICJza2ltciIsICJnZ2NvcnJwbG90IiwgImdncHViciIsICJEaWFncmFtbWVSIiwgInh0cyIsICJjb3VudHJ5Y29kZSIsICJjb3VudHJ5Y29kZSIsICJzaGlueSIpKQ0KDQpyZW1vdGVzOjppbnN0YWxsX2dpdGh1YigiaHJicm1zdHIvc3RyZWFtZ3JhcGgiKQ0KcmVtb3Rlczo6aW5zdGFsbF9naXRodWIoIm1hcnRpbmN0Yy9yd2EiKSAjIHINCmluc3RhbGwucGFja2FnZXMoIndhZmZsZSIsIHJlcG9zID0gImh0dHBzOi8vY2luYy5ydWQuaXMiKSAjd2FmZmxlIHBsb3QNCmluc3RhbGwucGFja2FnZXMoImdnY2hpY2tsZXQiLCByZXBvcyA9ICJodHRwczovL2NpbmMucnVkLmlzIikgIyBmb3Igcm91bmRlZCBjb3JuZXJzIA0KYGBgDQoNCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQ0KIyBpbXBvcnQgbGlicmFyeQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGdnY2hpY2tsZXQpDQpsaWJyYXJ5KGNvd3Bsb3QpDQpsaWJyYXJ5KGhyYnJ0aGVtZXMpDQpsaWJyYXJ5KGdnYWx0KQ0KbGlicmFyeShHR2FsbHkpDQpsaWJyYXJ5KHJ3YSkNCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KEhtaXNjKQ0KbGlicmFyeSh0aWJibGUpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShJU0xSKQ0KbGlicmFyeShza2ltcikNCmxpYnJhcnkoZ2djb3JycGxvdCkNCmxpYnJhcnkoZ2dwdWJyKQ0KbGlicmFyeSh4dHMpDQpsaWJyYXJ5KGNvdW50cnljb2RlKQ0KbGlicmFyeShwbG90bHkpDQpsaWJyYXJ5KHNoaW55KQ0KbGlicmFyeShzdHJlYW1ncmFwaCkNCmBgYA0KDQoNCiMjIERhdGEgaW1wb3J0DQoNCmBgYHtyLCByZXN1bHRzPSdoaWRlJ30NCmhhcHB5X2luZGV4XzIwMDUgPC0gIkRhdGEvd29ybGQtaGFwcGluZXNzLXJlcG9ydC0yMDA1LTIwMjAuY3N2IiANCmhhcHB5X2luZGV4XzIwMjEgPC0gIkRhdGEvd29ybGQtaGFwcGluZXNzLXJlcG9ydC0yMDIxLmNzdiINCmVtaXNzaW9uIDwtICJEYXRhL2NvMl9lbWlzc2lvbi5jc3YiDQpwb3B1bGF0aW9uIDwtIkRhdGEvcG9wdWxhdGlvbi5jc3YiDQoNCmRmXzIwMDUgPC0gcmVhZC5jc3YoaGFwcHlfaW5kZXhfMjAwNSkNCmRmXzIwMjEgPC0gcmVhZC5jc3YoaGFwcHlfaW5kZXhfMjAyMSkNCmRmX2VtaXNzIDwtIHJlYWQuY3N2KGVtaXNzaW9uLCBjb2wubmFtZXMgPSBjKCJFbnRpdHkiLCAiQ29kZSIgLCAiWWVhciIsICJjbzIiKSkNCmRmX3BvcCA8LSByZWFkLmNzdihwb3B1bGF0aW9uLCBjb2wubmFtZXMgPSBjKCJFbnRpdHkiLCAiQ29kZSIgLCAiWWVhciIsICJQb3B1bGF0aW9uIikpDQpgYGANCg0KVGhlIGZpcnN0IERhdGEgY29uc2lzdHMgb2YgdGhlIFVOIGhhcHBpbmVzcyBpbmRleCBmb3IgdGhlIHllYXJzIDIwMDUtMjAxNy4NCg0KYGBge3IsIGNvbGxhcHNlPVRSVUV9DQphc190aWJibGUoZGZfMjAwNSkNCmBgYA0KVGhlIHNlY29uZCBkYXRhIGlzIHRoZSBoYXBwaW5lc3MgaW5kZXggcmVwb3J0IGZvciAyMDIxLg0KDQpgYGB7ciwgY29sbGFwc2U9VFJVRX0NCmFzX3RpYmJsZShkZl8yMDIxKQ0KYGBgDQpUaGUgdGhpcmQgZGF0YSBjb250YWlucyBDTzIgZW1pc3Npb25zIGZyb20gYXJvdW5kIDE3MDAgdXAgdW50aWwgMjAxNywgYnkgY291bnRyaWVzIGFuZCBjb250aW5lbnRzLg0KDQpgYGB7ciwgY29sbGFwc2U9VFJVRX0NCmFzX3RpYmJsZShkZl9lbWlzcykNCmBgYA0KVGhlIGZpbmFsIGRhdGEgaXMgYSBsaXN0IG9mIHBvcHVsYXRpb24gc2l6ZXMgYnkgY291bnRyaWVzIGZvciBhYm91dCB0aGUgc2FtZSB5ZWFycyBhcyB0aGUgQ08yIGRhdGEuDQoNCmBgYHtyLCBjb2xsYXBzZT1UUlVFfQ0KYXNfdGliYmxlKGRmX3BvcCkNCmBgYA0KDQpBcyBzZWVuIGluIHRoZSB0YWJsZSBhYm92ZSwgdGhlIG1haW4gZGF0YXNldCByZWdhcmRpbmcgZW1pc3Npb25zIGhhcyBvbmx5IDQgZmVhdHVyZXMsIG9mIHdoaWNoIDIgYXJlIGlkZW50aWNhbCAoY291bnRyaWVzIGFuZCBjb3VudHJ5IGNvZGUpLiBXZSB3aWxsIG5vdyBleGFtaW5lIHRoZSBzdW1tYXJ5IG9mIGl0J3MgY2hhcmFjdGVyaXN0aWNzOg0KDQpgYGB7cn0NCnN1bW1hcnkoZGZfZW1pc3MpDQpgYGANCkFzIHNlZW4gYWJvdmUsIHdlIGNhbiBzZWUgdGhlIG1pbmltYWwgeWVhciwgbWluaW1hbCBhbW91bnQgb2YgQ08yIGVtaXNzaW9ucy4gQWxzbyBzaG93biBhcmUgbWVhbiBhbmQgbWF4IHZhbHVlcy4gDQpXZSBhbHNvIGxlYXJuIGFib3V0IHRoZSBzaXplIG9mIHRoZSBkYXRhLCBhcm91bmQgfjIxayByb3dzLiANCg0KIyBQYXJ0IDI6IFRpZHlpbmcgdGhlIERhdGENCg0KIyMgVGlkeWluZyBGdW5jdGlvbnMNCg0KYGBge3IsIGVjaG89RkFMU0V9DQoNCiMgYWRkICJkaWYiIGNvbHVtbg0KDQpkZl9lbWlzcyA8LWRmX2VtaXNzICU+JSANCiAgZ3JvdXBfYnkoRW50aXR5KSAlPiUNCiAgbXV0YXRlKERpZmYgPSBjbzIgLSBsYWcoY28yLCBkZWZhdWx0ID0gY28yWzFdKSkNCg0KI2ZpbHRlciB5ZWFyIHVwIDE5NTANCg0KZGZfcG9wX3RvX21lcmdlIDwtIGRmX3BvcCAlPiUNCiAgZmlsdGVyKFllYXIgPiAxOTQ5KQ0KDQpkZl9lbWlzc190b19tZXJnZSA8LSBkZl9lbWlzcyAlPiUNCiAgZmlsdGVyKFllYXIgPiAxOTQ5KQ0KDQojYXJyYW5nZSBkYXRhIHRvIG1lcmdlIGVtaXNzaW9uIGFuZCBwb3B1bGF0aW9uIA0KDQpkZl9lbWlzc190b19tZXJnZSRFbnRpdHkgPC0gYXMuY2hhcmFjdGVyKGRmX2VtaXNzX3RvX21lcmdlJEVudGl0eSkNCmRmX3BvcF90b19tZXJnZSRFbnRpdHkgPC0gYXMuY2hhcmFjdGVyKGRmX3BvcF90b19tZXJnZSRFbnRpdHkpDQoNCmRmX2FsbCA8LSBmdWxsX2pvaW4oZGZfZW1pc3NfdG9fbWVyZ2UsIGRmX3BvcF90b19tZXJnZSwgYnkgPSBjKCdFbnRpdHknLCdZZWFyJykpDQoNCmRyb3BzIDwtIGMoIkNvZGUueSIpDQpkZl9hbGwgPC1kZl9hbGxbLCAhKG5hbWVzKGRmX2FsbCkgJWluJSBkcm9wcyldDQoNCm5hbWVzKGRmX2FsbClbbmFtZXMoZGZfYWxsKSA9PSAiQ29kZS54Il0gPC0gIkNvZGUiDQoNCiNhZGQgY29sdW1uIG9mIG5vcm1hbGl6ZWQgZW1pc3Npb246IGNvMi9wb3B1bGF0aW9uIGJ5IHllYXIgKGF2Zy5yYXRpbykNCg0KZGZfYWxsIDwtIGRmX2FsbCAlPiUNCiAgbXV0YXRlKHJhdGlvID0gY28yL1BvcHVsYXRpb24pDQoNCiMjIyBDcmVhdGUgZGF0YWZyYW1lIGZvciBib3RoIDMwIHllYXJzIGF2ZXJhZ2UgYW5kIGJ5IGNvdW50cmllcw0KDQpuYW1lcyhkZl8yMDA1KQ0KbmFtZXMoZGZfMjAwNSlbbmFtZXMoZGZfMjAwNSkgPT0gIsOvLi5Db3VudHJ5Lm5hbWUiXSA8LSAiRW50aXR5Ig0KDQpkZl8yMDE3IDwtIGRmXzIwMDUgJT4lDQogIGZpbHRlcih5ZWFyID09IDIwMTcpJT4lDQogIHNlbGVjdChjKExpZmUuTGFkZGVyLCBFbnRpdHkpKQ0KDQpkZl9sYXN0XzMwIDwtIGRmX2FsbCAlPiUNCiAgZmlsdGVyKFllYXIgPj0gMTk4NykgJT4lDQogIG5hLm9taXQoKQ0KDQphZ2cxIDwtIGFnZ3JlZ2F0ZShkZl9sYXN0XzMwWyxjKCdyYXRpbycsICdQb3B1bGF0aW9uJywgJ2NvMicpXSwgDQogICAgICAgICAgICAgICAgICBsaXN0KGRmX2xhc3RfMzAkRW50aXR5KSwgbWVhbikgJT4lDQogIHNldF9uYW1lcyhubT1jKCdFbnRpdHknLCAnYXZnLnJhdGlvJywgJ2F2Zy5Qb3B1bGF0aW9uJywgJ2F2Zy5jbzInKSkNCg0KYWdnMiA8LSBhZ2dyZWdhdGUoZGZfbGFzdF8zMFssYygnRGlmZicpXSwNCiAgICAgICAgICAgICAgICAgIGxpc3QoZGZfbGFzdF8zMCRFbnRpdHkpLCBzdW0gKSAlPiUNCiAgc2V0X25hbWVzKG5tPWMoJ0VudGl0eScsICdzdW0uZGlmJykpDQoNCmRmXzIwMTckRW50aXR5IDwtIGFzLmNoYXJhY3RlcihkZl8yMDE3JEVudGl0eSkNCmFnZzEkRW50aXR5IDwtIGFzLmNoYXJhY3RlcihhZ2cxJEVudGl0eSkNCmFnZzIkRW50aXR5IDwtIGFzLmNoYXJhY3RlcihhZ2cyJEVudGl0eSkNCg0KZGZfbWVyZ2UgPC0gZnVsbF9qb2luKGFnZzEsIGRmXzIwMTcsIGJ5ID0gYygnRW50aXR5JykpICU+JQ0KICBmdWxsX2pvaW4oYWdnMikgJT4lDQogIG5hLm9taXQoKSAjIFRPRE8gY2hlY2sgd2h5IDIwIGNvdW50cmllcyB3ZXJlIHJlbW92ZWQNCg0KZGZfbWVyZ2UNCmBgYA0KDQpXZSBoYXZlIGp1c3QgY3JlYXRlZCB0aGUgdHdvIG1haW4gZGF0YXNldHMgdG8gd29yayB3aXRoLCB3aGljaCBpbmNsdWRlcyBpbXBvcnRhbnQgZmVhdHVyZXMgZnJvbSBhbGwgb2YgdGhlIHByZXZpb3VzIGRhdGFzZXRzIGFuZCBzb21lIGZlYXR1cmVzIHRoYXQgd2UgaGF2ZSBjcmVhdGVkIGFib3ZlOg0KDQoxLiAiZGZfYWxsIiB3aGljaCBpbmNsdWRlIGFsbCBkYXRhIHBlciBjb3VudHJ5IHBlciB5ZWFyIGZyb20gMTk1MCB1bnRpbCAyMDE3LCBpbnRyb2R1Y2luZyBzb21lIG5ldyBmZWF0dXJlczoNCiAgKiBQb3B1bGF0aW9uLCB0YWtlbiBmcm9tIHRoZSBwb3B1bGF0aW9uJ3MgREYNCiAgKiBDTzIvUG9wdWxhdGlvbiByYXRpbywgY2FsY3VsYXRlZC4NCiAgKiAiRGlmZiIgY29sdW1uLCB3aGljaCBzaG93cyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBwcmV2aW91cyBhbmQgdGhlIGN1cnJlbnQgeWVhciBlbWlzc2lvbnMgZm9yIGVhY2ggY29uc2VjdXRpdmUgeWVhci4NCiAgDQoyLiAiZGZfbWVyZ2UiLCB3aGljaCBpbmNsdWRlcyBkYXRhIGZvciBlYWNoIGNvdW50cnkgcmVnYXJkaW5nOg0KICAqIFRoZSBhdmVyYWdlIHJhdGlvIGZlYXR1cmUsIHdoaWNoIGlzIGNhbGN1bGF0ZWQgZnJvbSAxOTUwIHRvIDIwMTcgdXNpbmcgdGhlIHByZXZpb3VzbHkgZXhwbGFpbmVkICJyYXRpbyIgZmVhdHVyZS4gDQogICogVGhlIGRpZmZlcmVuY2UgaW4gY28yIGVtaXNzaW9uIHRoaXMgcGVyaW9kIGFuZCB0aGUgbGlmZS1sYWRkZXIgaW4gMjAxNy4NCiAgKiBUaGUgYXZlcmFnZSBwb3B1bGF0aW9uIGluIHRob3NlIHllYXJzLiANCiAgKiBUaGUgYXZlcmFnZSBDTzIgZW1pc3Npb25zLg0KICAqIFRoZSAyMDE3J3MgIkxpZmUuTGFkZGVyIiAtIGhhcHBpbmVzcyBpbmRleCBzY29yZS4gDQogICogIlN1bS5EaWYiIC0gc3VtbWluZyBvdmVyIHRoZSBkaWZmIGZlYXR1cmUuIA0KDQpXZSBhbHNvIG1hZGUgYSBjaG9pY2UgdG8gbGltaXQgb3VyIGRhdGEgcmVnYXJkaW5nIGVtaXNzaW9ucyB0byBhZnRlciAxOTUwLiBUaGUgcmVhc29uIGlzIHRoYXQgdGhlIHJpc2UgaW4gdmFsdWVzIGlzIGFsbW9zdCBleHBvbmVudGlhbCBhZnRlciB0aGUgeWVhcnMgb2YgV1cyLiBXaGVuIHBsb3R0ZWQgb24gYSBncmFwaCwgcGxhY2luZyB2YWx1ZXMgZnJvbSBiZWZvcmUgYW5kIGFmdGVyIDE5NTAgdGhleSBiZWNvbWUgaW5jb21wYXJhYmxlLiAgDQoNClRoZSBzdW1tYXJ5IGZvciBkZl9tZXJnZToNCg0KYGBge3IsIGNvbGxhcHNlPVRSVUV9DQpzdW1tYXJ5KGRmX21lcmdlKQ0KYGBgDQpBbmQgZm9yIGRmX2FsbDoNCmBgYHtyLCBjb2xsYXBzZT1UUlVFfQ0Kc3VtbWFyeShkZl9hbGwpDQpgYGANCiMgUGFydCAzOiBQcm9jY2VzaW5nIG9mIHRoZSBEYXRhDQoNCiMjIFZpc3VhbGlzYXRpb24gDQoNCiMjIyBDb3VudHJpZXMgb2YgdGhlIFdvcmxkDQpJbiB0aGlzIHBsb3QgdGhlIGRpZmZlcmVudCBjb3VudHJpZXMgaW4gdGhlIGRhdGEgYXJlIHNob3duIGluIGRlZXBlciBjb2xvcnMgZm9yIGhpZ2hlciB2YWx1ZXMgb2YgZW1pc3Npb24gdG8gcG9wdWxhdGlvbiByYXRpbyBpbiB0aGUgeWVhciBvZiAyMDE3Og0KDQpgYGB7ciwgZmlnLmFsaWduPSdjZW50ZXInLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KZCA9IGRmX2FsbCAlPiUNCiAgZmlsdGVyKFllYXI9PTIwMTcpDQoNCmwgPC0gbGlzdChjb2xvciA9IHRvUkdCKCJncmV5IiksIHdpZHRoID0gMC4yKQ0KDQojIHNwZWNpZnkgbWFwIHByb2plY3Rpb24vb3B0aW9ucw0KDQpnIDwtIGxpc3QoDQogIHNob3dmcmFtZSA9IEZBTFNFLA0KICBzaG93Y29hc3RsaW5lcyA9IEZBTFNFLA0KICBwcm9qZWN0aW9uID0gbGlzdCh0eXBlID0gJ01lcmNhdG9yJykNCikNCg0KcCA8LSBwbG90X2dlbyhkKSAlPiUNCiAgYWRkX3RyYWNlKA0KICAgIHogPSB+cmF0aW8sIGNvbG9yID0gfnJhdGlvLCBjb2xvcnMgPSAnUmVkcycsDQogICAgdGV4dCA9IH5FbnRpdHksIGxvY2F0aW9ucyA9IH5Db2RlLCBtYXJrZXIgPSBsaXN0KGxpbmUgPSBsKQ0KICApICU+JQ0KICBjb2xvcmJhcih0aXRsZSA9ICdDTzIvUG9wdWxhdGlvbicsIHRoaWNrbmVzcz0xNSkgJT4lDQogIGxheW91dCgNCiAgICB0aXRsZSA9ICdXb3JsZCBSYXRpbyBvZiBDTzIvUG9wdWxhdGlvbicsDQogICAgZ2VvID0gZywNCiAgICBhdXRvc2l6ZSA9IEYNCiAgKQ0KYGBgDQoNCg0KYGBge3IsIGZpZy5hbGlnbj0nY2VudGVyJywgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCnAgPC0gZ2dwbG90bHkocCwgd2lkdGggPSAzMDAwLCBoZWlnaHQgPSAxNTAwLCBhdXRvbWFyZ2luID0gVFJVRSkNCnANCmBgYA0KQXMgd2UgY2FuIHNlZSwgc29tZSBvZiB0aGUgbGVhZGluZyBjb3VudHJpZXMgaW4gQ08yL1BvcHVsYXRpb24gcmF0aW8gYXJlIFFhdGFyLCBVbml0ZWQgQXJhYiBFbWlyYXRlcywgS3V3YWl0LCBVU0EsIFNhdWRpIEFyYWJpYSwgQ2FuYWRhLCBLYXpha2hzdGFuIGFuZCBBdXN0cmFsaWEgd2l0aCBhYm92ZSAxNSB1bml0cyBvZiBDTzIvcG9wdWxhdGlvbi4NClRoYXQgbWVhbnMgY291bnRyaWVzIGxpa2UgQ2hpbmEgYW5kIEluZGlhIC0gd2hvc2UgQ08yIGVtaXNzaW9uIHJhdGUgaXMgdmVyeSBoaWdoIGNvbXBhcmVkIHRvIG90aGVyIGNvdW50cmllcyAtIGFyZSByYW5rZWQgbG93ZXIsIGV2ZW4gdGhvdWdoIHRoZXkgYXJlIG1vcmUgcG9sbHV0aW5nIGluIG5ldCBhbW91bnQuDQoNCiMjIyBDb3VudHJpZXMgRW1pc3Npb24gdnMgUG9wdWxhdGlvbiBieSBZZWFycyBhbmQgQ29udGluZW50cyANCg0KRm9yIGNvbWZvcnRhYmx5IGRpc3BsYXlpbmcgdGhlIGRhdGEsIGVhY2ggY291bnRyeSBpcyBhbGxvY2F0ZWQgdG8gaXQncyBmaXR0aW5nIGNvbnRpbmVudCBhbmQgYSBjb2xvci4gDQoNCmBgYHtyLCBpbmNsdWRlPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZCA8LSBkZl9hbGwgJT4lDQogIGZpbHRlcihZZWFyID4gMjAwMCkgJT4lDQogIGZpbHRlcihFbnRpdHkgIT0gJ1dvcmxkJykNCg0KZF9jb250PC0gZGF0YS5mcmFtZShjb3VudHJ5ID0gYyhkJEVudGl0eSkpDQoNCmRfY29udCRjb250aW5lbnQgPC0gY291bnRyeWNvZGUoc291cmNldmFyID0gZF9jb250WywgJ2NvdW50cnknXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmlnaW4gPSAiY291bnRyeS5uYW1lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXN0aW5hdGlvbiA9ICJjb250aW5lbnQiKQ0KDQpkJGNvbnRpbmVudCA8LSBkX2NvbnQkY29udGluZW50DQoNCmQgPC0gbmEub21pdChkKQ0KYGBgDQoNCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIGNvbGxhcHNlPVRSVUUsIHdhcm5pbmc9RkFMU0V9DQpmaWcgPC0gZCAlPiUNCiAgcGxvdF9seSgNCiAgICB4ID0gfmNvMiwgDQogICAgeSA9IH5Qb3B1bGF0aW9uLCANCiAgICBzaXplID0gfnJhdGlvLA0KICAgIGZyYW1lID0gflllYXIsIA0KICAgIHRleHQgPSB+RW50aXR5LCANCiAgICBjb2xvciA9IH5jb250aW5lbnQsDQogICAgdHlwZSA9ICdzY2F0dGVyJywNCiAgICBtb2RlID0gJ21hcmtlcnMnLA0KICAgIGhlaWdodCA9IDUwMCwNCiAgICB3aWR0aCA9IDkwMCwNCiAgICBhdXRvbWFyZ2luID0gVFJVRSANCiAgKQ0KDQpmaWcgPC0gZmlnICU+JSBsYXlvdXQoDQogICAgICB0aXRsZSA9ICJZZWFybHkgQ08yIEVtaXNzaW9ucyBieSBDb3VudHJpZXMgdnMgUG9wdWxhdGlvbiIsDQogICAgICB4YXhpcyA9IGxpc3QoDQogICAgICB0eXBlID0gImxvZyINCiAgICAgICMgYXV0b3NpemUgPSBGDQogICAgKQ0KICApDQoNCmZpZw0KYGBgDQpXZSB3b3VsZCBsaWtlIHRvIGRldmVsb3AgdGhpcyBncmFwaCBmb3J3YXJkIGFuZCBzZWUgaXQgd2l0aCBjb3JyZWxhdGlvbiB0byB0aGUgbGlmZSBsYWRkZXIgaW5kZXggZnJvbSAyMDA1LTIwMTcuIEZvciB0aGlzIHB1cnBvc2Ugd2Ugd291bGQgbGlrZSB0byBjcmVhdGUgYW5vdGhlciBkZiwgY29udGFpbmluZyBib3RoIGhhcHBpbmVzcyBpbmRleCBzY29yZXMgYW5kIGRhdGEgZnJvbSAiZGZfYWxsIiwgd2hpY2ggY29udGFpbnMgY29udGluZW50cyBkYXRhIGFzIHdlbGwgbm93OiANCg0KYGBge3IsIGVjaG89RkFMU0V9DQpkZl8yMDA1XzIwMTcgPC0gZCAlPiUNCiAgZmlsdGVyKFllYXIgPj0gMjAwNSkgJT4lDQogIG5hLm9taXQoKQ0KdGVtcCA8LSBkZl8yMDA1WyxjKCdFbnRpdHknLCAnTGlmZS5MYWRkZXInLCAneWVhcicpXSANCmNvbG5hbWVzKHRlbXApW2NvbG5hbWVzKHRlbXApID09ICJ5ZWFyIl0gPC0gIlllYXIiDQoNCmRmXzIwMDVfMjAxNyA8LWRmXzIwMDVfMjAxNyU+JQ0KICBmdWxsX2pvaW4odGVtcCwgYnk9YygiWWVhciIsICJFbnRpdHkiKSkNCmRmXzIwMDVfMjAxNw0KDQpkZl8yMDA1XzIwMTckUG9wdWxhdGlvbiA8LSBhcy5udW1lcmljKGRmXzIwMDVfMjAxNyRQb3B1bGF0aW9uKQ0KYGBgDQpXZSBnZXQgdGhlIGZvbGxvd2luZyBwbG90Og0KYGBge3IsIGNvbGxhcHNlPVRSVUUsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVjaG89VFJVRX0NCmZpZyA8LSBwbG90X2x5KA0KICAgIGRhdGEgPSBkZl8yMDA1XzIwMTcsDQogICAgeCA9IH5jbzIsIA0KICAgIHkgPSB+TGlmZS5MYWRkZXIsIA0KICAgIHNpemUgPSB+cmF0aW8sDQogICAgZnJhbWUgPSB+WWVhciwgDQogICAgdGV4dCA9IH5FbnRpdHksIA0KICAgIGNvbG9yID0gfmNvbnRpbmVudCwNCiAgICB0eXBlID0gJ3NjYXR0ZXInLA0KICAgIG1vZGUgPSAnbWFya2VycycsDQogICAgaGVpZ2h0ID0gNTAwLA0KICAgIHdpZHRoID0gOTAwLA0KICAgIGF1dG9tYXJnaW4gPSBUUlVFIA0KICApDQoNCmZpZyA8LSBmaWcgJT4lIGxheW91dCgNCiAgICAgIHRpdGxlID0gIlllYXJseSBDTzIgRW1pc3Npb25zIGJ5IENvdW50cmllcyB2cyBMaWZlIExhZGRlciIsDQogICAgICB4YXhpcyA9IGxpc3QoDQogICAgICB0eXBlID0gImxvZyINCiAgICApDQogICkNCg0KZmlnDQpgYGANClRoaXMgZ3JhcGggc2hvd3MgdGhlIENPMiBlbWlzc2lvbnMgb2YgZWFjaCBjb3VudHJ5IGNvbXBhcmVkIHRvIGl0J3MgcG9wdWxhdGlvbiBhbmQgTGlmZSBMYWRkZXIgc2NvcmUuIElmIHdlIGxvb2sgYXQgdGhlIFVuaXRlZCBTdGF0ZXMgZm9yIGV4YW1wbGUsIGl0IHNlZW1zIHRoYXQgd2hpbGUgdGhlIHBvcHVsYXRpb24gaGFzIGluY3JlYXNlZCwgdGhlIGxldmVsIG9mIHBvbGx1dGlvbiBoYXMgZGVjcmVhc2VkLg0KDQpBbmQgeWV0IGFub3RoZXIgc2NhdHRlciBwbG90IGZvciBkaWZmZXJlbnQgY291bnRyaWVzOg0KYGBge3IsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQpkZl8zZCA8LSBkZl8yMDA1XzIwMTcgJT4lDQogIGZpbHRlcihZZWFyID09IDIwMTcpDQoNCmZpZyA8LSBkZl8zZCAlPiUNCiAgcGxvdF9seSgNCiAgICB4ID0gflBvcHVsYXRpb24sIA0KICAgIHkgPSB+cmF0aW8sIA0KICAgIHogPSB+TGlmZS5MYWRkZXIsDQogICAgIyBzaXplID0gfkxpZmUuTGFkZGVyLA0KICAgICMgZnJhbWUgPSB+RW50aXR5LCANCiAgICB0ZXh0ID0gfkVudGl0eSwgDQogICAgY29sb3IgPSB+Y29udGluZW50LA0KICAgIGhlaWdodCA9IDUwMCwNCiAgICB3aWR0aCA9IDkwMCwNCiAgICBhdXRvbWFyZ2luID0gVFJVRSANCiAgKQ0KDQpmaWcgPC0gZmlnICU+JSBsYXlvdXQoDQogICAgICB0aXRsZSA9ICJDTzIgRW1pc3Npb25zIHZzIExpZmUgTGFkZGVyIHZzIFBvcHVsYXRpb24gYnkgQ291bnRyaWVzIg0KICAgICkNCg0KZmlnIDwtIGZpZyAlPiUgYWRkX21hcmtlcnMoKQ0KZmlnDQpgYGANCiMjIyBDb21tdWxhdGl2ZSBFbWlzc2lvbnMgYnkgQ291bnRyaWVzIE92ZXIgdGhlIFllYXJzIDE5NTAtMjAxNw0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRX0NCg0KZCA8LSBkZl9hbGwgJT4lDQogIGZpbHRlcihFbnRpdHkgIT0gIldvcmxkIikgJT4lDQogIGZpbHRlcihjbzIgIT0gMCkNCmQNCnBwIDwtIHN0cmVhbWdyYXBoKGQsIGtleT0iRW50aXR5IiwNCiAgICAgICAgICAgICAgICAgIG9yZGVyID0gImFzaXMiLA0KICAgICAgICAgICAgICAgICAgdmFsdWU9ImNvMiIsIA0KICAgICAgICAgICAgICAgICAgZGF0ZT0iWWVhciIsDQogICAgICAgICAgICAgICAgICBvZmZzZXQ9Inplcm8iLA0KICAgICAgICAgICAgICAgICAgc29ydD0iY28yIg0KICAgICAgICAgICAgICAgICAgKSAlPiUNCiAgc2dfYXhpc195KHRpY2tfZm9ybWF0ID0gImUiKSAgJT4lDQogIHNnX2xlZ2VuZChzaG93PVRSVUUsIGxhYmVsPSJDb3VudHJ5OiAiKSAlPiUNCiAgc2dfdGl0bGUoIkNPMiBFbWlzc2lvbnMgYnkgWWVhcnMgYW5kIENvdW50cmllcywgMTk1MC0yMDE3IikNCg0KcHANCg0KDQpgYGANClRoaXMgcGxvdCBzaG93cyB0aGUgYWNjdW11bGF0aW9uIG9mIGVtaXNzaW9ucyB5ZWFyIGFmdGVyIHllYXIsIGZyb20gMTk1MCB0byAyMDE3IGZvciBkaWZmZXJlbnQgY291bnRyaWVzLg0KDQojIyMgQ29tbXVsYXRpdmUgSGFwcGlubmVzcyBUcmVuZHMgaW4gU2luZ2xlIENvdW50cnkgDQoNClRoaXMgZ3JhcGggc2hvd3MgdGhlIGFjY3VtdWxhdGl2ZSBoYXBwaW5lc3MgaW5kZXggZm9yIGVhY2ggY291bnRyeSBmcm9tIDIwMDUgdG8gdGhlIHByZXNlbnQuIA0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnBwIDwtIHN0cmVhbWdyYXBoKGRmXzIwMDUsIGtleSA9ICJFbnRpdHkiLA0KICAgICAgICAgICAgICAgICAgIyBvcmRlciA9ICJyZXZlcnNlIiwNCiAgICAgICAgICAgICAgICAgIHZhbHVlPSJMaWZlLkxhZGRlciIsIA0KICAgICAgICAgICAgICAgICAgZGF0ZT0ieWVhciINCiAgICAgICAgICAgICAgICAgICMgb2Zmc2V0PSJ6ZXJvIiwNCiAgICAgICAgICAgICAgICAgICkgJT4lDQogIHNnX2ZpbGxfYnJld2VyKCJCbHVlcyIpICU+JQ0KICBzZ19sZWdlbmQoc2hvdz1UUlVFLCBsYWJlbD0iQ291bnRyeTogIikgJT4lDQogIHNnX3RpdGxlKCJIYXBwaW5lc3MgSW5kZXggYnkgWWVhcnMgYW5kIENvdW50cmllcywgMTk1MC0yMDE3IikgDQogIA0KcHANCg0KDQpgYGANCg0KIyMjIFllYXJseSBpbiBDTzIgRW1pc3Npb25zIGZvciBUb3AgMTAgUG9sbHV0aW5nIENvdW50cmllcw0KDQpgYGB7cn0NCnRvcF9lbWlzc18yMDE3IDwtIGRmX2VtaXNzICU+JQ0KICBmaWx0ZXIoWWVhciA9PSAyMDE3KSAlPiUNCiAgZmlsdGVyKENvZGUgIT0gJycpICU+JQ0KICBmaWx0ZXIoRW50aXR5ICE9ICJXb3JsZCIpICU+JQ0KICB0b3BfbiggMTAsIGNvMikgJT4lDQogIGFycmFuZ2UoZGVzYyhjbzIpKSAlPiUNCiAgaGVhZCgxMCkNCiAgDQp0b3BfY291bnRyaWVzID0gdG9wX2VtaXNzXzIwMTckRW50aXR5DQpgYGANCg0KYGBge3J9DQpnIDwtIGdncGxvdChkYXRhID0gZGZfZW1pc3NbZGZfZW1pc3MkRW50aXR5ICVpbiUgdG9wX2NvdW50cmllcywgXSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgLCBhZXMoeCA9IFllYXIsIHkgPSBjbzIsIGdyb3VwID0gRW50aXR5KSkgKyANCiAgICBnZW9tX2xpbmUoKSArDQogICAgbGFicyh0aXRsZSA9ICJUb3AgMTAgQ291bnRyaWVzIGJ5IENPMiBFbWlzc2lvbnMiKSArIA0KICAgIGdlb21fbGluZShhZXMoY29sID0gRW50aXR5KSkgKw0KICAgIHRoZW1lX2lwc3VtKCkNCmcgPC0gZ2dwbG90bHkoZywgaGVpZ2h0ID0gNTAwLA0KICAgIHdpZHRoID0gOTAwLA0KICAgIGF1dG9tYXJnaW4gPSBUUlVFKQ0KZw0KYGBgDQoNCg0KYGBge3J9DQpnIDwtIGdncGxvdChkYXRhID0gZGZfYWxsW2RmX2FsbCRFbnRpdHkgJWluJSB0b3BfY291bnRyaWVzLCBdIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAsIGFlcyh4ID0gWWVhciwgeSA9IHJhdGlvLCBncm91cCA9IEVudGl0eSkpICsgDQogICAgZ2VvbV9saW5lKGFlcyhjb2wgPSBFbnRpdHkpKSArIA0KICAgIGxhYnModGl0bGUgPSAiVG9wIDEwIENvdW50cmllcyBieSBDTzIgRW1pc3Npb25zIHRvIFBvcHVsYXRpb24gUmF0aW8iKSArDQogICAgdGhlbWVfaXBzdW0oKQ0KDQpnIDwtIGdncGxvdGx5KGcsIGhlaWdodCA9IDUwMCwNCiAgICB3aWR0aCA9IDkwMCwNCiAgICBhdXRvbWFyZ2luID0gVFJVRSkNCmcNCg0KYGBgDQpBY2NvcmRpbmcgdG8gdGhlc2UgdHdvIGdyYXBocywgdXNpbmcgdGhlIENPMi9Qb3B1bGF0aW9uIHJhdGlvIHdlIGNhbiBzZWUgdGhhdCBTYXVkaSBBcmFiaWEgZm9yIGV4YW1wbGUgaGFzIGEgbG93ZXIgcG9wdWxhdGlvbiB0aGFuIGNoaW5hLCBidXQgaW4gdGVybXMgb2YgcG9sbHV0aW9uIHBlciBwZXJzb24gaW4gMjAxNyBTYXVkaSBBcmFiaWEgaGFkIHRoZSBoaWdoZXN0IGVtaXNzaW9uIHBlciBwZXJzb24gcmF0aW8gaW4gdGhlIHdvcmxkLg0KDQojIyMgQm94cGxvdCBmb3IgdG9wIDEwIENvdW50cmllcyANCg0KYGBge3IsIGNvbGxhcHNlPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIGVjaG89VFJVRSwgd2FybmluZz1GQUxTRX0NCg0KZCA8LSBkZl9hbGxbZGZfYWxsJEVudGl0eSAlaW4lIHRvcF9jb3VudHJpZXMsIF0gDQpmaWcgPC0gcGxvdF9seShkLA0KICAgICAgICAgICAgICAgeCA9IH5FbnRpdHksDQogICAgICAgICAgICAgICB5ID0gfkRpZmYsDQogICAgICAgICAgICAgICB0eXBlID0gImJveCIsDQogICAgICAgICAgICAgICBjb2xvciA9IH5ZZWFyLA0KICAgICAgICAgICAgICAgaGVpZ2h0ID0gNTAwLA0KICAgICAgICAgICAgICAgIHdpZHRoID0gOTAwLA0KICAgICAgICAgICAgICAgIGF1dG9tYXJnaW4gPSBUUlVFKQ0KDQpmaWcgPC0gZmlnICU+JSAgbGF5b3V0KA0KICB0aXRsZSA9ICJEaWZmZXJlbmNlIGluIEVtaXNzaW9uIGZvciBUb3AgMTAgUG9sbHV0aW5nIENvdW50cmllcyIsDQogIGJveG1vZGUgPSAiZ3JvdXAiKQ0KZmlnDQogIA0KYGBgDQojIyMgVG9wIDEwIEhhcHBpZXN0IGNvdW50cmllcyBFbW1pc3Npb25zIGJ5IFllYXJzDQoNClRoaXMgZ3JhcGggdGFrZXMgdGhlIDEwIGhhcHBpZXN0IGNvdW50cmllcyBhbmQgc2hvd3MgdGhlIGRpc3RyaWJ1dGlvbiBvZiBDTzIgZW1pc3Npb25zIGRpZmZlcmVuY2UgbGV2ZWwgb2YgZW1pc3Npb24gYmV0d2VlbiAxOTUwIGFuZCAyMDE3Lg0KDQoNCmBgYHtyLCBjb2xsYXBzZT1UUlVFfQ0KDQp0b3BfMTBfaGFwcGluZXNzIDwtIGRmX21lcmdlICU+JQ0KICBmaWx0ZXIocmFuayhkZXNjKExpZmUuTGFkZGVyKSk8PTEwKQ0KDQpnIDwtIGdncGxvdChkYXRhID0gZGZfZW1pc3NbZGZfZW1pc3MkRW50aXR5ICVpbiUgdG9wXzEwX2hhcHBpbmVzcyRFbnRpdHksIF0gDQogICAgICAgICAgICAgICAgICAgICAgICAgICwgYWVzKHggPSBZZWFyLCB5ID0gY28yLCBncm91cCA9IEVudGl0eSkpICsgDQogICAgZ2VvbV9saW5lKCkgKw0KICAgIGxhYnModGl0bGUgPSAiVG9wIDEwIEhhcHBpZXN0IENvdW50cmllcyBieSBDTzIgRW1pc3Npb25zIikgKyANCiAgICB0aGVtZV9pcHN1bSgpICsNCiAgICBnZW9tX2xpbmUoYWVzKGNvbCA9IEVudGl0eSkpDQpnIDwtIGdncGxvdGx5KGcsIGhlaWdodCA9IDUwMCwNCiAgICB3aWR0aCA9IDkwMCwNCiAgICBhdXRvbWFyZ2luID0gVFJVRSkNCmcNCmBgYA0KSW4gdGhpcyBzZWN0aW9uIHdlIGFyZSBnb2luZyB0byBzdWdnZXN0IHR3byB0eXBlcyBvZiBjb3JyZWxhdGlvbiBiYXNlZCBvbiBvdXIgZXhwbG9yYXRpb24gb2YgdGhlIGRhdGE6DQoNCjEuIFRoZXJlIGlzIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIHRvdGFsIHRyZW5kIG9mIGVtaXNzaW9ucyBhbmQgdGhlIGN1cnJlbnQgaGFwcGluZXNzIGluZGV4Lg0KMi4gVGhlcmUgaXMgY29ycmVsYXRpb24gYmV0d2VlbiBjdXJyZW50IGVtaXNzaW9uIG5vcm1hbGl6ZWQgYnkgdGhlIHBvcHVsYXRpb24gdG8gdGhlIGN1cnJlbnQgaGFwcGluZXNzIGluZGV4Lg0KDQpgYGB7ciwgY29sbGFwc2U9VFJVRX0NCmcgPC0gZ2dwbG90KGRhdGEgPSBkZl9tZXJnZSwgYWVzKHggPSBhdmcucmF0aW8sIHkgPSBMaWZlLkxhZGRlcikpICsgDQogICAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gRW50aXR5KSkgKyANCiAgICBsYWJzKHRpdGxlID0gIkF2ZXJhZ2UgUmF0aW8gdnMgSGFwcGluZXNzIEluZGV4IikgKw0KICAgIHRoZW1lX2lwc3VtKCkgDQpnIDwtIGdncGxvdGx5KGcsIGhlaWdodCA9IDUwMCwNCiAgICB3aWR0aCA9IDkwMCwNCiAgICBhdXRvbWFyZ2luID0gVFJVRSkNCmcNCmBgYA0KDQpJbiB0aGUgZm9sbG93aW5nIHBsb3Qgd2UgaGF2ZSByZW1vdmVkIGNoaW5hIGFuZCBJbmRpYSBiZWNhdXNlIHRoZXkgYXJlIHNvcnQgb2YgIm91dGxpZXJzIiBpbiBhIHNlbnNlIHRoYXQgdGhleSBoYXZlIGRpc3BsYXllZCBtdWNoIGxhcmdlciBncm93IGluIGVtaXNzaW9ucyBjb21wYXJlZCB0byBvdGhlciBjb3VudHJpZXMsIHRoZXJlZm9yZSBtYWtpbmcgaXQgdmVyeSBoYXJkIHRvIGRpc3BsYXkgb24gdGhlIHNhbWUgcGxvdC4NCg0KDQpgYGB7ciwgY29sbGFwc2U9VFJVRX0NCmRmIDwtIHN1YnNldChkZl9tZXJnZSwgRW50aXR5ICE9ICJDaGluYSIgJiBFbnRpdHkgIT0gIkluZGlhIiApDQoNCmcgPC0gZ2dwbG90KGRhdGEgPSBkZiwgYWVzKHggPSBMaWZlLkxhZGRlciAsIHkgPSBzdW0uZGlmKSkgKyANCiAgICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBFbnRpdHkpKSArIA0KICAgIGxhYnModGl0bGUgPSAiU3VtIG9mIEVtaXNzaW9ucyBEaWZmZXJlbmNlIHZzIDIwMTcgSGFwcGluZXNzIEluZGV4IChDaGluYSwgSW5kaWEgZXguKSIpICsNCiAgICB0aGVtZV9pcHN1bSgpDQpnIDwtIGdncGxvdGx5KGcsIGhlaWdodCA9IDUwMCwNCiAgICB3aWR0aCA9IDkwMCwNCiAgICBhdXRvbWFyZ2luID0gVFJVRSkNCmcNCmBgYA0KDQogIyBQYXJ0IDQ6IE1vZGVsaW5nDQogDQogV2UgYXJlIG5vdyBnb2luZyB0byBpbnRyb2R1Y2UgdGhlIGxpbmVhciBtb2RlbDoNCiANCmBgYHtyLCBjb2xsYXBzZT1UUlVFfQ0KbGluZWFybW9kICA8LSBsbShMaWZlLkxhZGRlciB+IGF2Zy5yYXRpbywgZGF0YT1kZl9tZXJnZSkNCg0Kc3VtbWFyeShsaW5lYXJtb2QpDQpgYGANCg0KDQpgYGB7ciwgY29sbGFwc2U9VFJVRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCmNvbmZpbnQobGluZWFybW9kLCBsZXZlbD0wLjk1KQ0KcCA8LSBwbG90X2x5KA0KICB4ID0gZml0dGVkKGxpbmVhcm1vZCksDQogIHkgPSByZXNpZHVhbHMobGluZWFybW9kKSwNCiAgaGVpZ2h0ID0gNTAwLA0KICAgIHdpZHRoID0gOTAwLA0KICAgIGF1dG9tYXJnaW4gPSBUUlVFKQ0KDQpwPC0gcCAlPiUgbGF5b3V0KA0KICB0aXRsZSA9ICJSZXNpZHVhbCBwbG90IGZvciB0aGUgTGluZWFyIE1vZGVsIiwNCiAgYXV0b3NpemUgPSBULA0KICB5YXhpcyA9IGxpc3QodGl0bGUgPSAnUmVzaWR1YWxzJyksDQogIHhheGlzID0gbGlzdCh0aXRsZSA9ICdGaXR0ZWQgTGluZWFyIE1vZGVsJykNCiAgDQopDQoNCnANCmBgYA0KDQpBY2NvcmRpbmcgdG8gdGhlIGdyYXBoIHNob3duIGFib3ZlLCB0aGUgcG9pbnQgZGlzdGFuY2VzIGZyb20gdGhlIFgtYXhpcyBhcmUgcmVsYXRpdmVseSBlcXVhbC4gSXQncyBub3QgdW5lcXVpdm9jYWxseSwgaG93ZXZlciwgd2Ugc3RhdGUgdGhhdCB0aGlzIGdyYXBoIGlzIGhvbW9zY2VkYXN0aWMuDQoNCiMgVE9ETyBhZGQgaGVyZSBFWFBMQU5BVElPTg0KVGhlIHJlc2lkdWFsIHBsb3Qgc2hvd3Mgbm8gc2lnbnMgb2YgDQoNCg0KYGBge3IsIGNvbGxhcHNlPVRSVUV9DQpnIDwtIGdncGxvdChkZl9tZXJnZSwgYWVzKHggPSBhdmcucmF0aW8sIHkgPSBMaWZlLkxhZGRlcikpICsNCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gRW50aXR5KSkgKyANCiAgdGhlbWVfYncoKSArDQogIHN0YXRfc21vb3RoKG1ldGhvZCA9ICJsbSIpICsgDQogIGxhYnModGl0bGUgPSAiTGluZWFyIE1vZGVsbGluZyBIYXBwaW5lc3MgSW5kZXggYW5kIEF2ZXJhZ2UgUmF0aW8iKQ0KZyA8LSBnZ3Bsb3RseShnLCBoZWlnaHQgPSA1MDAsDQogICAgd2lkdGggPSA5MDAsDQogICAgYXV0b21hcmdpbiA9IFRSVUUpDQpnDQoNCg0KYGBgDQoNCkFjY29yZGluZyB0byB0aGUgbW9kZWwsIGl0IGNhbiBiZSBzZWVuIHRoYXQgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIGhhcHBpbmVzcyBpbmRleCBhbmQgdGhlIENPMiBlbWlzc2lvbiBpcyBub3QgaGlnaCwgYnV0IGl0IGRvZXMgZXhpc3QuIFdlIHdpbGwgZGlzY3VzcyBpdCBpbiB0aGUgY29uY2x1c2lvbnMgc2VjdGlvbi4NCg0KDQpgYGB7ciwgY29sbGFwc2UgPSBUUlVFfQ0KDQpudW1lcmljX3RpZHkgPC0gZGZfbWVyZ2VbLTFdDQoNCmNvcnJfZGF0YSA8LSBjb3IobnVtZXJpY190aWR5KQ0KDQpnIDwtIGdnY29ycnBsb3QoY29ycl9kYXRhLCBoYy5vcmRlciA9IFRSVUUsIHR5cGUgPSAibG93ZXIiLA0KICAgb3V0bGluZS5jb2wgPSAid2hpdGUiKSArDQogIGxhYnModGl0bGUgPSAiQ29ycmVsYXRpb24gTWF0cml4IikgKw0KICB0aGVtZV9pcHN1bSgpDQoNCmF4IDwtIGxpc3QoDQogIHRpdGxlID0gIiIsDQogIHNob3dncmlkID0gRkFMU0UpDQogIA0KZyA8LSBnZ3Bsb3RseShnLCBoZWlnaHQgPSA1MDAsDQogICAgd2lkdGggPSA5MDAsDQogICAgYXV0b21hcmdpbiA9IFRSVUUpICU+JQ0KICBsYXlvdXQoeGF4aXM9YXgsIHlheGlzPWF4KQ0KZw0KDQoNCmBgYA0KV2UgY2FuIHNlZSBpbiB0aGUgbWF0cml4IGFib3ZlIHRoYXQgdGhlcmUgYXJlIHNvbWUgY29ycmVsYXRpb24gdGhhdCBhcmUgZWFzeSB0byBleHBsYWluLCBzdWNoIGFzIGEgcHJldHR5IHN0cm9uZyBvbmUgYmV0d2VlbiB0aGUgc3VtIG9mIGRpZmZlcmVuY2VzIHJlZ2FyZGluZyBlbWlzc2lvbnMgb3ZlciB0aGUgdGVzdCBwZXJpb2QsIHRvIHRoZSBhdmVyYWdlIHNpemUgb2YgcG9wdWxhdGlvbi4gVGhlcmUgaXMgYWxzbyBhIHdlYWtlciBidXQgZXhpc3RpbmcgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgbGlmZSBsYWRkZXIgc2NhbGUgYW5kIHRoZSBhdmVyYWdlIHJhdGlvIG9mIENPMi9Qb3B1bGF0aW9uIHNpemUuIA0KVGhlIGZvbGxvd2luZyBzZWN0aW9uIHByZXNlbnRzIGFub3RoZXIgbW9kZWwgYW5kIGl0cyBzdW1tYXJ5Og0KDQpgYGB7ciwgY29sbGFwc2U9VFJVRSwgd2FybmluZz1GQUxTRX0NCmdtb2QgIDwtIGxtKExpZmUuTGFkZGVyIH4gbG9nKGF2Zy5yYXRpbyksIGRhdGE9ZGZfbWVyZ2UpDQoNCnN1bW1hcnkoZ21vZCkNCmBgYA0KDQoNCmBgYHtyLCBjb2xsYXBzZT1UUlVFLCB3YXJuaW5nPUZBTFNFfQ0KI3Bsb3QgeA0KDQpwIDwtIHFwbG90KHggPSBhdmcucmF0aW8sIExpZmUuTGFkZGVyLCBkYXRhPWRmX21lcmdlKQ0KcCA8LSBwICsgZ2VvbV9zbW9vdGgobWV0aG9kID0gImdsbSIsIGZvcm11bGEgPSB5fmxvZyh4KSwgZmFtaWx5ID0gYmlub21pYWwobGluayA9ICdsb2cnKSkgKw0KICBnZW9tX3BvaW50KGFlcyhjb2xvdXI9RW50aXR5KSkgKw0KICB0aGVtZV9pcHN1bSgpICsNCiAgbGFicyh0aXRsZSA9ICJMaW5lYXIgUmVncmVzc2lvbiBNb2RlbCAtIEF2ZXJhZ2UgUmF0aW8gdG8gTGlmZSBMYWRkZXIgU2NvcmUiKQ0KcCA8LSBnZ3Bsb3RseShwLCBoZWlnaHQgPSA1MDAsDQogICAgd2lkdGggPSA5MDAsDQogICAgYXV0b21hcmdpbiA9IFRSVUUpDQpwDQpgYGANCk9uIHRoaXMgbW9kZWwsIFdlIGNhbiBzZWUgYSB3ZWFrIGNvcnJlbGF0aW9uLCBidXQgYW4gZXhpc3Rpbmcgb25lIHRvIHRoZSBsb2dpc3RpYyByZWdyZXNzaW9uLiBJbnRlcmVzdGluZ2x5IGVub3VnaCwgVGhlICJoYXBwaWVzdCIgY291bnRyaWVzIHNlZW0gdG8gaGF2ZSBhIGhpZ2hlciByYXRpbyBvZiBDTzIgZW1pc3Npb25zIGFzIHdlbGwuIEFsc28gd29ydGggbWVudGlvbmluZyBmcm9tIHRoaXMgcGxvdDoNCiogVGhlIFVTIGlzIGxvY2F0ZWQgZmFyIHJpZ2h0IG9uIHRoaXMgbWFwLCBtZWFuaW5nIGl0J3MgZW1pdHRpbmcgYSBsb3Qgb2YgQ08yIGluIHByb3BvcnRpb24gdG8gaXRzIHBvcHVsYXRpb24sIGJ1dCBpdCBpcyBwcmV0dHkgaGlnaCBvbiB0aGUgaGFwcGluZXNzIGluZGV4IGFzIHdlbGwuIA0KKiBLdXdhaXQsIGJlaW5nIHRoZSBsZWFkZXIgb2YgdGhpcyB1bmZvcnR1bmF0ZSBjaGFyYWN0ZXJpc3RpYywgYWxzbyBoYXMgYSBwcmV0dHkgZGVjZW50IExpZmUgTGFkZGVyIHNjb3JlLiANCg0KDQojIyBUZXN0aW5nIHRoZSBUb3AgMzAgSGFwcGllc3QgQ291bnRyaWVzDQoNCg0KVG8gZnVydGhlciBjaGVjayBleGlzdGluZyBjb3JyZWxhdGlvbiwgd2Ugd291bGQgY29tcGFyZSB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgMzAgdG9wIHJhdGVkIGNvdW50cmllcyBpbiB0aGUgaGFwcGluZXNzIGluZGV4IGFuZCB0aGVpciBhdmcucmF0aW8gb2YgQ08yL1BvcHVsYXRpb24uIA0KSW4gdGhpcyBjYXNlLCB3ZSBoYXZlIHR3byB1bnJlbGF0ZWQgKGkuZS4sIGluZGVwZW5kZW50IG9yIHVucGFpcmVkKSBncm91cHMgb2Ygc2FtcGxlcy4gVGhlcmVmb3JlLCBpdCBpcyBwb3NzaWJsZSB0byB1c2UgYW4gaW5kZXBlbmRlbnQgdC10ZXN0IHRvIGV2YWx1YXRlIGhvdyB0aGVpciBtZWFucyBkaWZmZXIuIA0KDQoqICRtQSQgLSBXZWlnaHRlZCBhdmVyYWdlIG9mIHRoZSAzMCBtb3N0IGhhcHBpZXN0IGNvdW50cmllcy4NCiogJG1CJCAtIFdlaWdodGVkIGF2ZXJhZ2Ugb2YgdGhlIHJlc3Qgb2YgdGhlIGNvdW50cmllcy4NCg0KT3VyIHJlc2VhcmNoIHF1ZXN0aW9uczoNCg0KKiBJcyB0aGUgbWVhbiBhdmcucmF0aW8gb2YgdG9wIDMwIGhhcHBpZXN0IGNvdW50cmllcyAoJG1BJCkgaXMgZ3JlYXRlciB0aGFuIHRoZSBtZWFuIG9mIG90aGVyIGNvdW50cmllcyAoJG1CJCk/IA0KDQoqIElzIHRoZSB3ZWlnaHRlZCBhdmVyYWdlIG9mIHRoZSAzMCBoYXBwaWVzdCBjb3VudHJpZXMgKCRtQSQpIGdyZWF0ZXIgdGhhbiB0aGUgd2VpZ2h0ZWQgYXZlcmFnZSBvZiB0aGUgb3RoZXIgY291bnRyaWVzICgkbUIkKT8NCg0KSDA6ICRtQSQg4omlICRtQiQgIC0gVGhlIG51bGwgaHlwb3RoZXNpcw0KDQpIYTogJG1BJCA8ICRtQiQgKGxlc3MpIC0gVGhlIGFsdGVybmF0aXZlIGh5cG90aGVzaXMNCg0KDQpgYGB7cn0NCnRvcF8zMF9oYXBwaW5lc3MgPC0gZGZfbWVyZ2UgJT4lDQogIGZpbHRlcihyYW5rKGRlc2MoTGlmZS5MYWRkZXIpKTw9MzApDQoNCiMgQ3JlYXRlIGEgZGF0YSBmcmFtZQ0KVF9kYXRhIDwtIGRmX21lcmdlICU+JQ0KICBzZWxlY3QoRW50aXR5LCBhdmcucmF0aW8sKSAlPiUNCiAgbXV0YXRlKGdyb3VwID0gaWZlbHNlKEVudGl0eSAlaW4lIHRvcF8zMF9oYXBwaW5lc3MkRW50aXR5LCAiVG9wIDMwIENvbnRyaWVzIiwgIk90aGVyIENvdW50cmllcyIpKSANCg0KZyA8LSBnZ2JveHBsb3QoVF9kYXRhLCB4ID0gImdyb3VwIiwgeSA9ICJhdmcucmF0aW8iLCANCiAgICAgICAgICBjb2xvciA9ICJncm91cCIsIHBhbGV0dGUgPSBjKCIjMDBBRkJCIiwgIiNFN0I4MDAiKSwNCiAgICAgICAgeWxhYiA9ICJhdmcuIHJhdGlvIiwgeGxhYiA9ICJHcm91cCIpICsNCiAgdGhlbWVfaXBzdW0oKSArDQogIGxhYnModGl0bGUgPSAiQXZlcmFnZSBSYXRpbyBDb21wYXJlZCAtIFRvcCAzMCBDb3VudHJpZXMgdnMgT3RoZXIgQ291bnRyaWVzIikNCg0KZyA8LSBnZ3Bsb3RseShnLCBoZWlnaHQgPSA1MDAsDQogICAgd2lkdGggPSA5MDAsDQogICAgYXV0b21hcmdpbiA9IFRSVUUpDQpnDQoNCg0KYGBgDQoNCkFsdGhvdWdoIG5vdCBkcmFtYXRpYywgaXQgaXMgb2J2aW91cyB0aGF0IHNvbWUgY29ycmVsYXRpb24gZG9lcyBleGlzdC4gV2Ugd291bGQgbGlrZSB0byBmdXJ0aGVyIGNoZWNrOg0KDQoqIERvIHRoZSB0d28gZ3JvdXAgaGF2ZSB0aGUgc2FtZSB2YXJpYW5jZXM/DQoqIFdlIHdpbGwgdXNlIEYtdGVzdCB0byB0ZXN0IGZvciBob21vZ2VuZWl0eSBpbiB2YXJpYW5jZXMuIA0KDQpgYGB7cn0NCnJlcy5mdGVzdCA8LSB2YXIudGVzdChhdmcucmF0aW8gfiBncm91cCwgZGF0YSA9IFRfZGF0YSkNCnJlcy5mdGVzdA0KDQpgYGANClRoZSBwLXZhbHVlIG9mIEYtdGVzdCBpcyBwID0gMC4xMTIgd2hpY2ggaXMgZ3JlYXRlciB0aGFuIHRoZSBzaWduaWZpY2FuY2UgbGV2ZWwgMC4wNS4NCkluIGNvbmNsdXNpb24sIHRoZXJlIGlzIG5vIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgdmFyaWFuY2VzIG9mIHRoZSB0d28gZGF0YSBzZXRzLiBUaGVyZWZvcmUsIHdlIHVzZWQgdGhlIFQtdGVzdCBhbmQgYXNzdW1lZCB0aGF0IHRoZSB2YXJpYW5jZXMgYXJlIGVxdWFsIC0gYWNjb3JkaW5nIHRvIGNhc2UgMiBvZiBoeXBvdGhlc2lzIHRlc3RpbmcuDQoNCmBgYHtyfQ0KDQojIENvbXB1dGUgdC10ZXN0DQpyZXMgPC0gdC50ZXN0KGF2Zy5yYXRpbyB+IGdyb3VwLCBkYXRhID0gVF9kYXRhLCB2YXIuZXF1YWwgPSBUUlVFLCBhbHRlcm5hdGl2ZSA9ICJsZXNzIikNCnJlcw0KDQpgYGANClRoZSBwLXZhbHVlIG9mIHRoZSB0ZXN0IGlzICQzLjEwM2UtMDckLCB3aGljaCBpcyBsZXNzIHRoYW4gdGhlIHNpZ25pZmljYW5jZSBsZXZlbCAkXGFscGhhID0gMC4wNSQuIFdlIGNhbiBjb25jbHVkZSB0aGF0IHRvcCAzMCBhdmVyYWdlIGF2Zy5yYXRpbyBpcyBzaWduaWZpY2FudGx5IGRpZmZlcmVudCBmcm9tIHRoZSBvdGhlciBjb3VudHJpZXMgYXZlcmFnZSBhdmcucmF0aW8gd2l0aCBhICRwdmFsdWUgPSAzLjEwM2UtMDckLg0KDQojIENvbmNsdXNzaW9uDQoNCkdlbmVyYWxseSwgcmVnYXJkaW5nIG91ciBiYXNlIGFzc3VtcHRpb25zLCB3ZSB3ZXJlIHN1cnByaXNlZCB0byBzZWUgdGhhdCB0aGV5IHdlcmUgYWN0dWFsbHkgbm90IG9ubHkgd3JvbmcsIGJ1dCBhbG1vc3Qgb3Bwb3NpdGUuIHdoaWxlIHZlcnkgdW5kZXZlbG9wZWQgY291bnRyaWVzLCBsaWtlIGNvdW50cmllcyBpbiBBZnJpY2EgbW9zdGx5LCBoYXZlIGEgdmVyeSBsb3cgcG9sbHV0aW9uIGluZGV4IGFuZCBsaWZlIGxhZGRlciBpbmRleC4gT24gdGhlIG90aGVyIGhhbmQsIHNvbWUgdmVyeSBkZXZlbG9wZWQgY291bnRyaWVzIGhhdmUgaGlnaGVyIHZhbHVlcyBvbiBib3RoIGluZGV4ZXMuIFRoZXJlIGFyZSBhbHNvIGEgbG90IG9mIGNvdW50cmllcyB3aG8gZG9uJ3QgZml0IHRob3NlIGFzc3VtcHRpb25zIGF0IGFsbC4gDQoNCkRlc3BpdGUgdGhpcywgb3VyIGZpbmFsIHRlc3RzIGRpZCBzaG93IHNvbWUgd2VhayBjb3JyZWxhdGlvbiB3aXRoaW4gdGhlIHRvcCAzMCBjb3VudHJpZXMgYXMgc2hvd24uDQoNCndlIHN0aXB1bGF0ZSB0aGF0IHRoZXNlIHdlYWsgY29ycmVsYXRpb25zIGFyZSBjYXVzZWQgcGFydGlhbGx5IGJlY2F1c2Ugb2YgdGhlIGZhY3QgdGhhdCB0aGUgaGFwcGluZXNzIGluZGV4IGlzIGEgKnN1cnZleSogYmFzZWQgZGF0YS4gDQppdCBtZWFucyB0aGF0IGl0IGlzIHBvc3NpYmxlIHRoYXQgdGhlIGNpdGl6ZW5zIG9mIGEgY291bnRyeSBhcmUgbm90IG5lY2Vzc2FyaWx5IGF3YXJlIG9mIHRoZSBDTzIgcG9sbHV0aW9uIGFuZCBpdCdzIGNvbnNlcXVlbmNlcy4gVGhlcmUgYXJlIGFsc28gb3RoZXIgZmFjdG9ycyB0aGF0IGFmZmVjdCB0aGUgaGFwcGluZXNzIGluZGV4IGxpa2Ugd2VsZmFyZSAsIGNvcnJ1cHRpb24sICBoZWFsdGggc2VydmljZXMsIHdlYWx0aCBldGMuDQoNCk9uIHRoZSBvdGhlciBoYW5kOg0KMS4gSXQgY2FuIGJlIGFzc3VtZWQgdGhhdCBhIGNvdW50cnkgdGhhdCBlbWl0cyBtb3JlIENPMiBpcyBhIG1vcmUgbW9kZXJuIGFuZCB0ZWNobm9sb2dpY2FsbHkgYWR2YW5jZWQgY291bnRyeSwgdGhlcmVmb3JlIGl0IGlzIG1vcmUgZXN0YWJsaXNoZWQsIGl0cyBjaXRpemVucyBmZWVsIGEgc2Vuc2Ugb2YgcHJvZ3Jlc3MsIGFuZCB0aGF0IGNhdXNlcyB0aGUgaGFwcGluZXNzIGluZGV4IHRvIHJpc2UuDQoyLiBJbiBtb3JlIHBvbGx1dGluZyBjb3VudHJpZXMgLSBpdCBpcyBhIHBvc3NpYmxlIHRoYXQgdGhlcmUgYXJlIG1vcmUgd29ya3BsYWNlcywgdGhlcmVmb3JlIHRoZXNlIGNvdW50cmllcyB3aWxsIGhhdmUgYSBsb3dlciB1bmVtcGxveW1lbnQgcmF0ZSAtIHdoaWNoIGNhbiBpbiB0dXJuIGluY3JlYXNlIHRoZSBsZXZlbCBvZiBoYXBwaW5lc3MgaW5kZXggd2l0aGluIHRoZSBjb3VudHJ5Lg0KDQoNCkluIGNvbmNsdXNpb24sIGluIG91ciBvcGluaW9uLCB0aGUgcGVvcGxlIG1heSBiZSBhd2FyZSBvZiB0aGVpciBjb3VudHJ5IENPMiBlbWlzc2lvbnMsIHlldCBpdCBkb2Vzbid0IG5lY2Vzc2FyaWx5IHNob3cgaW4gdGhlIGhhcHBpbmVzcyBpbmRleCBzdXJ2ZXkuDQoNCkFub3RoZXIgdGhpbmcgdG8gY29uc2lkZXIgaXMgdGhhdCBlbnZpcm9ubWVudGFsIHByZXNlcnZhdGlvbiwgcG9sbHV0aW9uIHJlZHVjdGlvbiBhbmQgZ2xvYmFsIHdhcm1pbmcgYXJlIHF1aXRlIHRyZW5kaW5nIGluIHRoZSBsYXN0IGZldyB5ZWFycywgYnV0IHRoaXMgaXMgYSB2ZXJ5IGNvbXBsZXggc3lzdGVtIG9mIGRlcGVuZGVuY2llcywgYW5kIHRoZSByYXRlIG9mIHdoaWNoIGNoYW5nZXMgYXJlIG5vdGljZWFibGUgaXMgcmFwaWRseSBjaGFuZ2luZy4gSXQgaXMgdW5rbm93biB3aGV0aGVyIHdlIGhhdmUgY3Jvc3NlZCB0aGUgbm9uLXJldHVybiBwb2ludCBmb3IgbWFraW5nIHRoZSBwbGFuZXQgdG9vIGhvdCB0byBsaXZlIGF0IGR1ZSB0byB0aG9zZSBlbWlzc2lvbnMsIGJ1dCB0aW1lIHdpbGwgdGVsbC4gDQoNCg0KDQoNCg==